/*
 * TODO:
 *   - use swig to pass in/out arrays
 *   - remove any unused functions
 *   - allocate rav elts in blocks, with array of pointers so we still 
 *     have good efficiency, but don't have to allocate everything at once
 *   - evaluate hash function
 *   - probably get rid of low-freq code
 */
#ifndef __RAV_H__
#define __RAV_H__

#include<stdint.h>

#define USE_FFT 1

#define DEFAULT_MAX_RAV_ELTS 50000
#define DEFAULT_RAV_ELT_VECT_ENTRIES 2048

#define RAV_WORD 0
#define RAV_FEATURE 1
#define RAV_VALUE 2

typedef long int rav_index_t;

/* hash table */

#define RAV_HASH_NBITS 16
#define RAV_HASH_ENTRIES (1<<RAV_HASH_NBITS)
#define RAV_HASH_MASK (RAV_HASH_ENTRIES-1)

/* hash table element */

typedef struct rav_hash_elt {
   struct rav_hash_elt *next;
   double *ctx;
} rav_hash_elt_t;

/* in uint64_t's */
#define LOW_FREQ_SHIFT 6
#define LOW_FREQ_MASK 0x3f

/* hash table structure */

typedef struct rav_hash {
   rav_hash_elt_t *hash_ary;
   double *ctx_ary;
   double *env_ary;
   char **name_ary;
   uint64_t *low_freq;
   rav_index_t cur_idx;
   unsigned long total_name_size;
   unsigned orig_random_seed;
   unsigned cur_random_seed;
   unsigned dim;
   unsigned max_elts;
   unsigned low_freq_size;
   double inv_sqrt_max_elts;
} rav_hash_t;

/* allocation */
extern rav_hash_t *rav_init(int random_seed, int max_elts, int vect_entries);
extern void rav_destroy(rav_hash_t *h);

/* adding/deleting/accessing */
#define FREQ_OK 0
#define FREQ_LOW 1
#define FREQ_HIGH 1
extern rav_index_t rav_new(rav_hash_t *h, const char *s, int freq_code);
#define LOOKUP_WORD 0
#define LOOKUP_FEATURE 1
extern rav_index_t rav_lookup(rav_hash_t *h, const char *s, int reason);
extern char *rav_get_name(rav_hash_t *h, rav_index_t idx);
extern long int rav_num_unique(rav_hash_t *h);
extern long int rav_get_tmp_idx(rav_hash_t *h);
extern int rav_delete(rav_hash_t *h, const char *s);

/* accumulating/binding */
extern void rav_set(rav_hash_t *h, rav_index_t dst, rav_index_t src);
extern void rav_add(rav_hash_t *h, rav_index_t dst, rav_index_t src);
extern void rav_normalize(rav_hash_t *h, rav_index_t tgt);

extern void rav_clr_ctx(rav_hash_t *h, rav_index_t tgt);
extern void rav_acc(rav_hash_t *h, rav_index_t src);
extern void rav_acc_from_ctx(rav_hash_t *h, rav_index_t src);
extern void rav_add_acc(rav_hash_t *h, rav_index_t dst);
extern void rav_cconv_add(rav_hash_t *h, rav_index_t dst, rav_index_t a, rav_index_t b);

/* searching */
extern double rav_cosine(rav_hash_t *h, rav_index_t idx1, rav_index_t idx2);
extern void rav_closest(rav_hash_t *h, rav_index_t tgt_idx, int n, int include_tgt);
extern rav_index_t rav_closest_idx_n(rav_hash_t *h, int type, int n);
extern double rav_closest_score_n(rav_hash_t *h, int type, int n);
extern char *rav_closest_name_n(rav_hash_t *h, int type, int n);

/* saving/loading/debug */
extern int rav_save(rav_hash_t *h, int fileno);
extern int rav_load(rav_hash_t *h, int fileno);
extern void rav_dbg(rav_hash_t *h, rav_index_t idx);
extern void rav_dump(rav_hash_t *h, const char *fname, int n, int include_values);
extern void rav_dump_names(rav_hash_t *h, const char *fname, int n, int include_values);

#endif
